package com.bookmanagement.service;

import com.bookmanagement.entity.Book;
import com.bookmanagement.entity.Borrowing;
import com.bookmanagement.mapper.BorrowingMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// @Service注解：标识该类为Spring管理的业务逻辑层组件，负责处理借阅相关的核心业务
@Service
public class BorrowingService {

    // 自动注入BorrowingMapper（数据访问层），用于与数据库交互处理借阅记录
    @Autowired
    private BorrowingMapper borrowingMapper;
    // 自动注入BookService（图书业务层），用于调用图书相关的业务逻辑（如查询图书状态、更新图书状态）
    @Autowired
    private BookService bookService;

    // @Transactional注解：声明该方法为事务方法，确保所有数据库操作（插入借阅记录+更新图书状态）要么同时成功，要么同时失败
    @Transactional
    public void createBorrowing(Borrowing borrowing, Long userId) {
        // 1. 查询图书信息，验证是否可借
        Book book = bookService.findById(borrowing.getBookId()); // 通过图书ID查询图书详情
        if (!book.getStatus().equals("AVAILABLE")) { // 若图书状态不是"可借"（AVAILABLE）
            throw new RuntimeException("图书不可借"); // 抛出异常，终止借阅流程
        }
        // 2. 校验借阅时间的合理性（借阅时间不能晚于应还时间）
        if (borrowing.getBorrowTime().isAfter(borrowing.getDueTime())) {
            throw new RuntimeException("借阅时间不能晚于应还时间"); // 时间不合理则抛异常
        }
        // 3. 完善借阅记录信息
        borrowing.setUserId(userId); // 设置借阅人ID
        borrowing.setStatus("BORROWED"); // 标记借阅状态为"已借出"
        borrowing.setCreateTime(LocalDateTime.now()); // 记录创建时间（当前时间）
        borrowing.setUpdateTime(LocalDateTime.now()); // 记录更新时间（当前时间）
        // 4. 插入借阅记录到数据库
        borrowingMapper.insertBorrowing(borrowing);
        // 5. 更新图书状态为"已借出"（BORROWED）
        book.setStatus("BORROWED");
        bookService.updateBook(book); // 调用BookService更新图书信息
    }

    public boolean hasBorrowingConflict(Long bookId) {
        return borrowingMapper.countActiveBorrowings(bookId) > 0;
    }

    @Transactional
    public void returnBorrowing(Long id) {
        Borrowing borrowing = borrowingMapper.findById(id);
        if (borrowing == null) {
            throw new RuntimeException("借阅记录不存在");
        }
        if (borrowing.getStatus().equals("RETURNED")) {
            throw new RuntimeException("图书已归还");
        }
        borrowing.setStatus("RETURNED");
        borrowing.setReturnTime(LocalDateTime.now());
        borrowing.setUpdateTime(LocalDateTime.now());
        borrowingMapper.updateBorrowing(borrowing);
        Book book = bookService.findById(borrowing.getBookId());
        book.setStatus("AVAILABLE");
        bookService.updateBook(book);
    }

    public List<Borrowing> getBorrowingsByUser(Long userId) {
        return borrowingMapper.findByUserId(userId);
    }
    // 多条件分页查询借阅记录（主要用于管理员筛选）
    public Map<String, Object> getAllBorrowings(int pageNum, int pageSize, LocalDateTime borrowDate, String bookTitle, String username) {
        // 计算分页偏移量（从第几条记录开始查询，如第2页、每页10条，则偏移量为10）
        int offset = Math.max((pageNum - 1) * pageSize, 0);
        // 1. 分页查询符合条件的借阅记录
        List<Borrowing> borrowings = borrowingMapper.findAllWithFilters(offset, pageSize, borrowDate, bookTitle, username);
        // 2. 统计符合条件的总记录数（用于计算总页数）
        long total = borrowingMapper.countAllWithFilters(borrowDate, bookTitle, username);
        // 3. 封装结果为前端分页组件所需的格式
        Map<String, Object> result = new HashMap<>();
        result.put("items", borrowings); // 当前页的借阅记录列表
        result.put("total", total); // 总记录数
        return result;
    }

    // 统计月度借阅趋势（用于生成趋势图）
    public Map<String, Object> getBorrowTrendStats() {
        // 1. 从mapper获取月度统计数据（包含"month"和"count"字段）
        List<Map<String, Object>> stats = borrowingMapper.countBorrowingsByMonth();
        // 2. 提取月份标签（如["2025-01", "2025-02"]）
        List<String> labels = stats.stream()
                .map(s -> s.get("month").toString()) // 转换为字符串格式
                .toList();
        // 3. 提取每月借阅数量（如[120, 150]）
        List<Long> values = stats.stream()
                .map(s -> (Long) s.get("count")) // 转换为Long类型
                .toList();
        // 4. 封装为前端图表所需格式
        Map<String, Object> result = new HashMap<>();
        result.put("labels", labels);
        result.put("values", values);
        return result;
    }


    // 统计逾期费用与借阅时长的关系（用于分析费用规则）
    public List<List<Object>> getOverdueFeeStats() {
        // 调用mapper获取统计数据，转换为包含"时长"和"费用"的嵌套列表
        return borrowingMapper.getOverdueFeeStats().stream()
                .map(s -> List.of(s.get("duration"), s.get("overdueFee"))) // 每个子列表包含时长和费用
                .toList();
    }

    // 按班级和月份统计借阅数量（多维度统计，用于分析各班级借阅行为）
    public Map<String, Object> getClassBorrowingStats() {
        // 1. 获取原始统计数据（包含班级、月份、借阅量）
        List<Map<String, Object>> stats = borrowingMapper.countBorrowingsByClassAndMonth();

        // 2. 生成最近6个月的列表（如当前是2025-06，则生成2025-01至2025-06）
        List<String> months = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM"); // 格式化月份为"年-月"
        YearMonth currentMonth = YearMonth.now(); // 获取当前月份
        for (int i = 5; i >= 0; i--) { // 循环生成前5个月到当前月
            months.add(currentMonth.minusMonths(i).format(formatter));
        }

        // 3. 获取所有不重复的班级名称
        List<String> classNames = stats.stream()
                .map(s -> s.get("className").toString()) // 提取班级名
                .distinct() // 去重
                .sorted() // 排序
                .toList();

        // 4. 为每个班级生成对应月份的借阅数据（无数据则补0）
        List<Map<String, Object>> series = classNames.stream().map(className -> {
            List<Long> data = months.stream()
                    .map(month -> stats.stream()
                            // 匹配当前班级和月份的记录
                            .filter(s -> s.get("month").equals(month) && s.get("className").equals(className))
                            .findFirst() // 取匹配的第一条记录
                            .map(s -> (Long) s.get("count")) // 提取借阅量
                            .orElse(0L)) // 无记录则为0
                    .toList();

            // 封装该班级的统计数据（用于柱状图展示）
            Map<String, Object> serie = new HashMap<>();
            serie.put("name", className); // 班级名
            serie.put("type", "bar"); // 图表类型为柱状图
            serie.put("data", data); // 各月份的借阅量
            serie.put("stack", "total"); // 堆叠显示（增强视觉对比）
            return serie;
        }).toList();

        // 5. 封装最终结果
        Map<String, Object> result = new HashMap<>();
        result.put("classNames", classNames); // 班级列表
        result.put("months", months); // 月份列表
        result.put("series", series); // 各班级的月度数据
        return result;
    }

    // @Transactional：事务方法，确保费用支付状态更新的原子性(支付逾期费用)
    @Transactional
    public void payOverdueFee(Long id, Long userId) {
        // 1. 查询借阅记录是否存在
        Borrowing borrowing = borrowingMapper.findById(id);
        if (borrowing == null) {
            throw new RuntimeException("借阅记录不存在");
        }

        // 2. 更新记录状态为"已支付逾期费用"
        borrowing.setStatus("OVERDUE_PAID");
        borrowing.setUpdateTime(LocalDateTime.now()); // 更新时间
        borrowingMapper.updateBorrowing(borrowing); // 保存更新
    }



    // 续期最大天数常量（限制续期范围）
    private static final int MAX_RENEWAL_DAYS = 30;
    // @Transactional：事务方法，确保续期操作的原子性
    @Transactional
    public void renewBorrowing(Long id, Long userId, Integer renewalDays) {
        // 1. 校验续期天数是否合理（1到30天之间）
        if (renewalDays == null || renewalDays < 1 || renewalDays > MAX_RENEWAL_DAYS) {
            throw new RuntimeException("续期天数必须在 1-" + MAX_RENEWAL_DAYS + " 之间");
        }
        // 2. 查询借阅记录是否存在
        Borrowing borrowing = borrowingMapper.findById(id);
        if (borrowing == null) {
            throw new RuntimeException("借阅记录不存在");
        }
        // 注释代码：原本用于校验续期人是否为借阅人（当前逻辑跳过该校验）
//        if (!borrowing.getUserId().equals(userId)) {
//            throw new RuntimeException("无权续期此记录");
//        }
        // 3. 检查图书是否已归还（已归还不可续期）
        if ("RETURNED".equals(borrowing.getStatus())) {
            throw new RuntimeException("已归还图书不可续期");
        }
        // 4. 计算新的应还时间（原应还时间+续期天数）
        LocalDateTime newDueTime = borrowing.getDueTime().plusDays(renewalDays);
        borrowing.setDueTime(newDueTime); // 更新应还时间
        // 5. 若原状态为逾期，且新应还时间在当前时间之后，恢复为"已借出"状态
        if ("OVERDUE".equals(borrowing.getStatus()) && newDueTime.isAfter(LocalDateTime.now())) {
            borrowing.setStatus("BORROWED");
        }
        // 6. 更新记录的更新时间并保存
        borrowing.setUpdateTime(LocalDateTime.now());
        borrowingMapper.updateBorrowing(borrowing);
    }

    @Transactional
    public void deleteBorrowing(Long id) {
        Borrowing borrowing = borrowingMapper.findById(id);
        if (borrowing == null) {
            throw new RuntimeException("借阅记录不存在");
        }
        // 如果图书仍在借阅中，恢复图书状态为 AVAILABLE
        if ("BORROWED".equals(borrowing.getStatus()) || "OVERDUE".equals(borrowing.getStatus())) {
            Book book = bookService.findById(borrowing.getBookId());
            book.setStatus("AVAILABLE");
            bookService.updateBook(book);
        }
        borrowingMapper.deleteBorrowing(id);
    }
}